/**
 *	@author: Kathleen Go
 *	date created: April 23, 2006
 *	version: 1.0
 *  modified: May 20, 2006
 */

package text.learning;

import java.util.Vector;
import java.util.Hashtable;
import java.util.Iterator;

import text.obj.TExtChunk;
import text.util.TExtLearnerUtility;
import text.learning.TExtChunkLexicon;

public class TExtChunkSplitter{
	
	Vector vAlignedSourceChunks;
	Vector vAlignedTargetChunks;
	Vector vOrigSourceChunks;
	Vector vOrigTargetChunks;
	Vector vFunction1;
	Vector vFunction2;
	Vector vFcnPrefix1;
	Vector vFcnPrefix2;
	TExtChunkLexicon chunkLex;
	TExtLearnerUtility tlu;
	boolean bSourceIsFilipino;
	Vector vFinalResult;
	
	protected TExtChunkSplitter(boolean bSourceIsFilipino, TExtLearnerUtility tlu){
		Vector vFunctionWords = tlu.getFunctionWords();
		this.tlu = tlu;
		this.vFunction1 = (Vector)vFunctionWords.get(0);
		this.vFunction2 = (Vector)vFunctionWords.get(1);
		Vector vFcnAffix = tlu.getFunctionWordsPrefix();
		vFcnPrefix1 = (Vector)vFcnAffix.get(0);
		vFcnPrefix2 = (Vector)vFcnAffix.get(1);
		this.bSourceIsFilipino = bSourceIsFilipino;
		if(bSourceIsFilipino)
			chunkLex = new TExtChunkLexicon('e');
		else
			chunkLex = new TExtChunkLexicon('f');
	}
	
	/**	This returns the Vector of possible alignments for the given Source and Target chunks.
	 *
	 *	@return a {@link Vector} containing the possible alignments (in {@link Vector} form)
	 *		for the given chunk.
	 *
	 *	index [0..n] - Vector containing the details of each possible alignments such that for
	 *		one possible alignment:
	 *		
	 *		index 0 - {@link String} index mapping of the splitted chunks and the index mapping of Source-to-Target alignment
	 *		index 1 - {@link Vector} containing the new Source {@link TExtChunk}s in the original order
	 *		index 2 - {@link Vector} containing the new Target {@link TExtChunk}s in the original order
	 *		index 3 - {@link Vector} containing the aligned Source {@link TExtChunk}s
	 *		index 4 - {@link Vector} containing the aligned Target {@link TExtChunk}s
	 *			such that the first element in index 3 is aligned to first element in index 4
	 */
	protected Vector getFinalResult(){
		return vFinalResult;
	}
	
	/**	This is the main method for the alignment process of the given Source and Target chunks.
	 * 
	 *	Returns the a primitive boolean to indicate if there is at least one possible
	 *		alignment for the given set of Source and Target chunks.
	 *
	 *	@param vSourceChunks a {@link Vector} containing the set of Source objects
	 *	@param vTargetChunks a {@link Vector} containing the set of Target objects
	 *	@param alignedWords a {@link Hashtable} containing the aligned tokens of the Source and Target chunks
	 *	@return the primitive boolean that indicates if there are valid alignments for the given chunks
	 *		true - there at least one possible alignment for the given chunks
	 *		false - there are no possible alignments for the given chunks
	 */
	protected boolean alignChunks(Vector vSourceChunks, Vector vTargetChunks, Hashtable alignedWords, int nTemp){
	//	System.out.println("*********************************************");
	//	JOptionPane.showMessageDialog(null, nTemp);
		
		TExtChunkAligner txtChunkAlign = new TExtChunkAligner(bSourceIsFilipino, tlu.getFunctionWords(), alignedWords);
		
		Vector vDummy;
		vOrigSourceChunks = (Vector)vSourceChunks.clone();
		vOrigTargetChunks = (Vector)vTargetChunks.clone();
		Vector vRemovedS = new Vector(vSourceChunks.size());
		Vector vRemovedT = new Vector(vTargetChunks.size());
		Vector vRemainingSInd = new Vector(vSourceChunks.size());
		Vector vRemainingTInd = new Vector(vTargetChunks.size());
		for(int i = 0; i < vSourceChunks.size(); i++)
			vRemainingSInd.add(new Integer(i));
		for(int i = 0; i < vTargetChunks.size(); i++)
			vRemainingTInd.add(new Integer(i));
	
		// check Chunks DB if there are chunk pairs that can be used in the alignment
		vDummy = txtChunkAlign.useExistingChunksDB((Vector)vSourceChunks.clone(), (Vector)vTargetChunks.clone());
		vSourceChunks = (Vector)vDummy.get(0);
		vTargetChunks = (Vector)vDummy.get(1);
		vRemovedS = (Vector)vDummy.get(2);
		vRemovedT = (Vector)vDummy.get(3);
		
		for(Iterator it = vRemovedS.iterator(); it.hasNext(); )
			vRemainingSInd.remove(it.next());
		for(Iterator it = vRemovedT.iterator(); it.hasNext(); )
			vRemainingTInd.remove(it.next());
		vDummy = txtChunkAlign.getCurrentAlignedChunks();
		vAlignedSourceChunks = (Vector)vDummy.get(0);
		vAlignedTargetChunks = (Vector)vDummy.get(1);
	// end
	
		
	// check if there is still a need to proceed to the next filter
		if(vAlignedSourceChunks.size() == vOrigSourceChunks.size() &&
			vAlignedTargetChunks.size() == vOrigTargetChunks.size()){

			Vector vCandAlignment = new Vector(5);
			vCandAlignment.add("****" + makeAlMapping(vRemovedS, vRemovedT));
			vCandAlignment.add(vOrigSourceChunks);
			vCandAlignment.add(vOrigTargetChunks);
			vCandAlignment.add(vAlignedSourceChunks);
			vCandAlignment.add(vAlignedTargetChunks);
			vFinalResult = new Vector(1);
			vFinalResult.add(vCandAlignment);
			return true;
		}

		else if(vAlignedSourceChunks.size() == vOrigSourceChunks.size() ||
			vAlignedTargetChunks.size() == vOrigTargetChunks.size())
				return false;
	// end
	
	// check if there are aligned Chunks (without splitting)
		int i = 0;
		int[][] arrScores = new int[vSourceChunks.size()][vTargetChunks.size()];
		int[][] arrContent = new int[vSourceChunks.size()][vTargetChunks.size()];
		Vector vCSourceWithTarget = new Vector(vSourceChunks.size());
		Vector vSourcePOVMap = new Vector(vSourceChunks.size());
		Vector vTargetPOVMap = new Vector(vSourceChunks.size());
		for(Iterator it = vSourceChunks.iterator(); it.hasNext(); ){
			TExtChunk cSource = (TExtChunk)it.next();
			vDummy = txtChunkAlign.alignFromAlignedWords(cSource, vTargetChunks, 'a', true);
			arrScores[i] = (int[])vDummy.get(0);
			vSourcePOVMap.add((Vector)vDummy.get(2));
			vTargetPOVMap.add((Vector)vDummy.get(3));
			int nCTargetIndex = getCorrTarget(i, arrScores, vTargetChunks.size(), vCSourceWithTarget, (Vector)vSourcePOVMap.get(i));
			vCSourceWithTarget.add(new Integer(nCTargetIndex));
			i++;
		}
//
		txtChunkAlign = null;
//
		int nCtr = 0;
		
		for(int k = 0; k < vCSourceWithTarget.size(); k++){
			int nTargetIndex = ((Integer)vCSourceWithTarget.get(k)).intValue();
			if(nTargetIndex != -1){
				
				vRemovedS.add(vRemainingSInd.get(nCtr));
				vRemainingSInd.remove(nCtr);
				vRemovedT.add(vRemainingTInd.get(nTargetIndex));
				vRemainingTInd.remove(nTargetIndex);
				for(int m = k+1; m < vCSourceWithTarget.size(); m++)
					if(((Integer)vCSourceWithTarget.get(m)).intValue() > nTargetIndex)
						vCSourceWithTarget.setElementAt(new Integer(((Integer)vCSourceWithTarget.get(m)).intValue()-1), m);
				vCSourceWithTarget.remove(k);
				k--;
				vAlignedSourceChunks.add(vSourceChunks.remove(nCtr));
				vAlignedTargetChunks.add(vTargetChunks.remove(nTargetIndex));
				vSourcePOVMap.remove(nCtr);
				vTargetPOVMap.remove(nCtr);
				int nTargetPOVMapSize = vTargetPOVMap.size(); 
				for(int j = 0; j < nTargetPOVMapSize; j++){
					Vector vMapElement = (Vector)vSourcePOVMap.get(j);
					vMapElement.remove(nTargetIndex);
					vSourcePOVMap.setElementAt(vMapElement, j);

					vMapElement = (Vector)vTargetPOVMap.get(j);
					vMapElement.remove(nTargetIndex);
					vTargetPOVMap.setElementAt(vMapElement, j);
				}
			}else{
				nCtr++;
			}
		}
	// end

	
	// check if there is still a need to proceed to the next filter
		if(vAlignedSourceChunks.size() == vOrigSourceChunks.size() &&
			vAlignedTargetChunks.size() == vOrigTargetChunks.size()){
				
			Vector vCandAlignment = new Vector(5);
			vCandAlignment.add("****" + makeAlMapping(vRemovedS, vRemovedT));
			vCandAlignment.add(vOrigSourceChunks);
			vCandAlignment.add(vOrigTargetChunks);
			vCandAlignment.add(vAlignedSourceChunks);
			vCandAlignment.add(vAlignedTargetChunks);
			vFinalResult = new Vector(1);
			vFinalResult.add(vCandAlignment);
			return true;
		}
			
		else if(vAlignedSourceChunks.size() == vOrigSourceChunks.size() ||
			vAlignedTargetChunks.size() == vOrigTargetChunks.size())
				return false;
	// end
		
		Vector vCandDivi = new Vector();
		Vector vCandDiviRanges = new Vector();
		for(int j = 0; j < vSourceChunks.size(); j++){
			Vector vResults = checkFragmentsFromChunksDB((TExtChunk)vSourceChunks.get(j), vTargetChunks,
				(Vector)vSourcePOVMap.get(j), (Vector)vTargetPOVMap.get(j));
			vSourcePOVMap.setElementAt(((Vector)vResults.get(0)).clone(), j);
			vTargetPOVMap.setElementAt(((Vector)vResults.get(1)).clone(), j);
		
			Vector vCand = getCandidateAlignments((TExtChunk)vSourceChunks.get(j),
				(Vector)vSourcePOVMap.get(j), (Vector)vTargetPOVMap.get(j));
			vCandDivi.add(vCand.get(0));
			vCandDiviRanges.add(vCand.get(1)); 
		}

		Vector vFinalCand = removeOverlapAlignment(vCandDivi, vCandDiviRanges);
		Vector vFinalSourceCandidates = (Vector)((Vector)vFinalCand.get(0)).clone();
		Vector vFinalSCandRanges = (Vector)((Vector)vFinalCand.get(1)).clone();
	// end
		vFinalResult = splitChunks(vFinalSourceCandidates, vFinalSCandRanges,
			vSourceChunks, vTargetChunks, vRemainingSInd, vRemainingTInd, vRemovedS,
			vRemovedT);
		if(vFinalResult.size() == 0)
			return false;
		vFinalResult = removeDupAl(vFinalResult);
		for(Iterator it = vFinalResult.iterator(); it.hasNext(); ){
			Vector vCandAlignment = (Vector)it.next();
		
		}
	//	JOptionPane.showMessageDialog(null, "With Final Result");
/******/	
		return true;
	}
	
	
	
	
	
	
	
	
	
	
	/*	This function checks the Chunks DB if unaligned fragments of the given Source chunk
	 *		can be aligned to unaligned fragments of any of the remaining Target chunks.
	 *	Returns a Vector containing the revised Source-to-Targets mapping and
	 *		Targets-to-Source mapping if there are applicable fragments found.
	 */
	protected Vector checkFragmentsFromChunksDB(TExtChunk cSource, Vector vTarget, Vector vMapSrc, Vector vMapTar){
		boolean bCandidate;
		Vector vMapDummyS = new Vector();
		Vector vMapDummyT = new Vector();
		
		if(cSource.size() > 0){
			int nSource = 0;
			for(Iterator it1 = vMapSrc.iterator(); it1.hasNext(); ){
				Vector vSrcIndexMap = (Vector)it1.next();
				bCandidate = false;
				for(Iterator it2 = vSrcIndexMap.iterator(); it2.hasNext(); ){
					int nTarget = ((Integer)it2.next()).intValue();
					if(nTarget == -1)
						bCandidate = true;
				}
				if(!bCandidate){
					nSource++;
					continue;
				}
				Vector vTarIndexMap = (Vector)vMapTar.get(nSource);
				bCandidate = false;
				for(Iterator it2 = vTarIndexMap.iterator(); it2.hasNext(); ){
					int nTarget = ((Integer)it2.next()).intValue();
					if(nTarget == -1)
						bCandidate = true;
				}
				if(((TExtChunk)vTarget.get(nSource)).size() == 0)
					bCandidate = false;
				if(bCandidate){
					for(int nCtr = 0; nCtr < vSrcIndexMap.size(); nCtr++){
						int nTarget = ((Integer)vSrcIndexMap.get(nCtr)).intValue();
						if(nTarget == -1){
							Object oSrcToken = cSource.get(nCtr);
							if(oSrcToken instanceof String){
								String strChunkQuery;
								if(nCtr == 0)
									strChunkQuery = oSrcToken.toString().replace("'", "''") + "%";
								else if(nCtr == vSrcIndexMap.size() - 1)
									strChunkQuery = "%" + oSrcToken.toString().replace("'", "''");
								else
									strChunkQuery = "%" + oSrcToken.toString().replace("'", "''") + "%";
								Vector vLookUpChunks = chunkLex.lookup(strChunkQuery);
								if(vLookUpChunks != null){
									Vector vSTMapIndex = checkIfApplicable(vLookUpChunks, vSrcIndexMap, (Vector)vMapTar.get(nSource), nCtr, cSource, (TExtChunk)vTarget.get(nSource));
									if(vSTMapIndex != null){
										vSrcIndexMap = (Vector)vSTMapIndex.get(0);
										vMapTar.setElementAt((Vector)vSTMapIndex.get(1), nSource);
										nCtr = nCtr + ((Integer)vSTMapIndex.get(2)).intValue() - 1;
									}
								}
							}
						}
					}
				}
				vMapSrc.setElementAt(vSrcIndexMap, nSource);
				nSource++;
			}
		}
		Vector vResults = new Vector(2);
		vResults.add(vMapSrc);
		vResults.add(vMapTar);
		return vResults;
	}

	/*	This function performs the actual checking of the retrieved chunks from the Chunks DB 
	 *		if it can be applied to an unaligned fragment of the given Source chunk and 
	 *		unaligned fragment of the given Target chunk.
	 *	Returns a Vector containing the possibly revised Source-to-Targets mapping and
	 *		Targets-to-Source mapping if there are applicable fragments found.
	 */
	protected Vector checkIfApplicable(Vector vLookUpChunks, Vector vSrcIndexMap
		, Vector vTarIndexMap, int nCtr, TExtChunk cSource, TExtChunk cTarget){
		
		for(int i = vLookUpChunks.size()-1; i >= 0; i-=2){
			TExtChunk cTTemp = (TExtChunk)vLookUpChunks.get(i);
			TExtChunk cSTemp = (TExtChunk)vLookUpChunks.get(i-1);
			
			if(cSTemp.size() == 0 || cTTemp.size() == 0){
				vLookUpChunks.remove(i);
				vLookUpChunks.remove(i-1);
			}
		}
		if(vLookUpChunks.size() == 0)
			return null;
		
		Vector vMatchedST = new Vector();
		Vector vNewMapS = new Vector();
		Vector vNewMapT = new Vector();
		
		String strStartSource = (String)cSource.get(nCtr);

		int nMatchedST = 0;
		for(Iterator it = vLookUpChunks.iterator(); it.hasNext(); ){
			int j = nCtr;
			TExtChunk cLookUpSource = (TExtChunk)it.next();
			TExtChunk cLookUpTarget = (TExtChunk)it.next();
			int nOffsetS = 0;
			for(Iterator it2 = cLookUpSource.iterator(); it2.hasNext(); ){
				if(strStartSource.compareToIgnoreCase(it2.next().toString()) == 0)
					break;
				nOffsetS++;
			}
			int nStartRunS = nCtr-nOffsetS;
			if(nStartRunS >= 0 && nStartRunS+cLookUpSource.size() <= cSource.size()){
				boolean bCheckTarget = true;
				Vector vSourceAligned = new Vector();
				
				int nSumLimit = nStartRunS+cLookUpSource.size();
				for(int i = nStartRunS; i < nSumLimit; i++){
					Object oSrcToken = cSource.get(i);
					Object oLUToken = cLookUpSource.get(i-nStartRunS);
					if((oSrcToken instanceof String && ((String)oSrcToken).compareToIgnoreCase(oLUToken.toString()) != 0)
						|| (oSrcToken instanceof TExtChunk && (oLUToken instanceof String || (vSrcIndexMap.get(i) instanceof Integer && ((Integer)vSrcIndexMap.get(i)).intValue() < 0)))){
						
						bCheckTarget = false;
						break;
					}
					else if(vSrcIndexMap.get(i) instanceof Integer && ((Integer)vSrcIndexMap.get(i)).intValue() < 0)
						nMatchedST++;
					else if(vSrcIndexMap.get(i) instanceof String){
						bCheckTarget = false;
						break;
					}
					else if(vSrcIndexMap.get(i) instanceof Integer && ((Integer)vSrcIndexMap.get(i)).intValue() != -1)
						vSourceAligned.add(new Integer(i));
				}
				if(bCheckTarget){
					Vector vCandTarIndex = new Vector(1);
					int nTarCtr = 0;
					boolean bTarApp = false;
					Object oLUToken = cLookUpTarget.get(0);
						
					for(Iterator it2 = cTarget.iterator(); it2.hasNext(); ){
						if(oLUToken instanceof TExtChunk && it2.next() instanceof TExtChunk)
							vCandTarIndex.add(new Integer(nTarCtr));
						else if(oLUToken instanceof String && it2.next().toString().compareToIgnoreCase((String)oLUToken) == 0)
							vCandTarIndex.add(new Integer(nTarCtr));
						nTarCtr++;
					}
					for(int i = 0; i < vCandTarIndex.size(); i++){
						int nCurrTarIndex = ((Integer)vCandTarIndex.get(i)).intValue();
						Vector vTargetAligned = new Vector(1);
						Vector vSourceAlignedTemp = (Vector)vSourceAligned.clone();
						if(nCurrTarIndex+cLookUpTarget.size() <= cTarget.size()){
							boolean bCheckRemAlign = true;
							boolean bHasUnaligned = false;
							boolean bHasNextAligned = false;
							Vector vUnAlignedIndex = new Vector();
							int nStartUnAligned = -1;
							int nSumLimit2 = nCurrTarIndex+cLookUpTarget.size();
							for(int k = nCurrTarIndex; k < nSumLimit2 && bCheckRemAlign; k++){
								Object oSrcFromTarPOV = vTarIndexMap.get(k);
								Object oTarToken = cTarget.get(k);
								Object oLUTarToken = cLookUpTarget.get(k-nCurrTarIndex);
								if((oTarToken instanceof String && ((String)oTarToken).compareToIgnoreCase(oLUTarToken.toString()) != 0)
									|| (oTarToken instanceof TExtChunk && (oLUTarToken instanceof String || (oSrcFromTarPOV instanceof Integer && ((Integer)oSrcFromTarPOV).intValue() == -1)))){
									
									bCheckRemAlign = false;
									break;
								}
								else if((oTarToken instanceof TExtChunk && oLUTarToken instanceof TExtChunk)){
									if(oSrcFromTarPOV instanceof Integer){
										if(((Integer)oSrcFromTarPOV).intValue() == -1
											|| ((Integer)oSrcFromTarPOV).intValue() == -999)
											
											bCheckRemAlign = false;
										else if(vSourceAligned.contains(oSrcFromTarPOV)
											&& cLookUpSource.get(((Integer)oSrcFromTarPOV).intValue()-nStartRunS).toString().compareTo(cLookUpTarget.get(k-nCurrTarIndex).toString()) == 0){
										
											vTargetAligned.add(new Integer(k));
										}
											
										else{
											bCheckRemAlign = false;
										}
									}
									else
										bCheckRemAlign = false;
								}
								
								else if(oSrcFromTarPOV instanceof String || (oSrcFromTarPOV instanceof Integer && ((Integer)oSrcFromTarPOV).intValue() > -1)){
									if(oSrcFromTarPOV instanceof String){
										bCheckRemAlign = false;
										break;
									}
									else if(!vSourceAligned.contains(oSrcFromTarPOV)){
										bCheckRemAlign = false;
										break;
									}
										
									vTargetAligned.add(new Integer(k));
								}
								else if(oSrcFromTarPOV instanceof Integer && ((Integer)oSrcFromTarPOV).intValue() < 0){
									vUnAlignedIndex.add(new Integer(k));
								}

							}
							if(bCheckRemAlign && vUnAlignedIndex.size() > 0){
								boolean isAllAligned = true;
								for(int k = vSourceAlignedTemp.size()-1; k >= 0 && isAllAligned; k--){
									Object oTargetPos = vSrcIndexMap.get(((Integer)vSourceAlignedTemp.get(k)).intValue());
									if(oTargetPos instanceof String){
										String strPrev = (String)oTargetPos;
										String strRange[] = ((String)oTargetPos).split("_");
										int nLBound = Integer.parseInt(strRange[0]);
										int nUBound = Integer.parseInt(strRange[1]);
										boolean bTargetFound = true;
										for(int m = nUBound; m >= nLBound && bTargetFound; m--)
											bTargetFound = vTargetAligned.remove(new Integer(m));

										if(bTargetFound){
											do{
												vSourceAlignedTemp.remove(k);
												k--;
												if(k >= 0)
													oTargetPos = vSrcIndexMap.get(((Integer)vSourceAlignedTemp.get(k)).intValue());
											}while(k >= 0 && oTargetPos instanceof String && strPrev.compareTo((String)oTargetPos) == 0);
											if(k >= 0)
												k++;
										}
										else
											isAllAligned = false;
									}
									else if(oTargetPos instanceof Integer && ((Integer)oTargetPos).intValue() != -999){
										isAllAligned = vTargetAligned.remove(oTargetPos);
										vSourceAlignedTemp.remove(k);
									}
								}
								
								if(isAllAligned && vSourceAlignedTemp.size() == 0 && vTargetAligned.size() == 0){
									bTarApp = true;
									Vector vNewSrcMap = (Vector)vSrcIndexMap.clone();
									Vector vNewTarMap = (Vector)vTarIndexMap.clone();
									for(int k = nStartRunS; k < nStartRunS+cLookUpSource.size(); k++)
										vNewSrcMap.setElementAt(nCurrTarIndex + "_" + (nCurrTarIndex + cLookUpTarget.size() - 1), k);
									for(int k = nCurrTarIndex; k < nCurrTarIndex + cLookUpTarget.size(); k++)
										vNewTarMap.setElementAt(nStartRunS + "_" + (nStartRunS+cLookUpSource.size()-1), k);
									vNewMapS.add(vNewSrcMap.clone());
									vNewMapT.add(vNewTarMap.clone());
								}
							}
						}
						else
							break;
						if(bTarApp)
							break;
					}
					if(bTarApp)
						vMatchedST.add(new Integer(cLookUpSource.size()));
				}
			}
		}

		int nMaxMatched = 0;
		int nMaxMatchedIndex = -1;
		int i = 0;
		for(Iterator it = vMatchedST.iterator(); it.hasNext(); ){
			int nTemp = ((Integer)it.next()).intValue();
			if(nTemp > nMaxMatched){
				nMaxMatched = nTemp;
				nMaxMatchedIndex = i;
			}
		}
		
		if(nMaxMatchedIndex != -1){
			Vector vResults = new Vector(3);
			vResults.add(vNewMapS.get(nMaxMatchedIndex));
			vResults.add(vNewMapT.get(nMaxMatchedIndex));
			vResults.add(vMatchedST.get(nMaxMatchedIndex));
			return vResults;
		}
		return null;
	}

	/*	Given a Source chunk, this looks for the Target Chunk which it is exactly aligned to
	 *		such that every token in that Target must be aligned to the given Source and
	 *		vice versa.
	 *	Returns the index of the chosen Target Chunk or -1 if there are none.
	 */
	protected int getCorrTarget(int nSourcePtr, int[][] arrScores, int nTargetChunks, Vector vTakenTargetIndex, Vector vSrcMapIndex){
		for(int i = 0; i < nTargetChunks; i++)
			if(arrScores[nSourcePtr][i] != -1 && !vTakenTargetIndex.contains(new Integer(i))){
				boolean bAllAligned = true;
				for(Iterator it = ((Vector)vSrcMapIndex.get(i)).iterator(); it.hasNext(); )
					if(((Integer)it.next()).intValue() == -1)
						bAllAligned = false;
				if(bAllAligned)
					return i;				
			}
		
		return -1;
	}
	
	/**	This function gets the candidates for splitting a Source chunk (cSource) which are
	 *		basically identifying the boundaries of splitting.
	 *
	 *	vMapElementS - contains the Source-to-Target alignment matrix of cSource
	 *	vMapElementT - contains the Target-to-Source alignment matrix for cSource
	 *
	 *	Returns all the possible ways cSource can be split which is, all the possible
	 *		boundaries identified in cSource.
	 */
	protected Vector getCandidateAlignments(TExtChunk cSource, Vector vMapElementS, Vector vMapElementT){
		Vector vRangeListS;
		int nSourceTokens;
		
		if(cSource.size() == 0)
			nSourceTokens = 1;
		else
			nSourceTokens = cSource.size();
		vRangeListS = new Vector(nSourceTokens);
		for(int i = 0; i < nSourceTokens; i++)
			vRangeListS.add(new Vector());

		int nTargetPtr = 0;
		for(Iterator it1 = vMapElementS.iterator(), it2 = vMapElementT.iterator(); it1.hasNext() && it2.hasNext(); ){
			Vector vMapS = (Vector)it1.next();
			Vector vMapT = (Vector)it2.next();
			Object oPrev;
			int nNumSSubChunks = 0;
			for(int i = 0; i < vMapS.size(); i++){
				nNumSSubChunks++;
				oPrev = vMapS.get(i);
				Vector vAlignedSequenceIndex = new Vector();
				Vector vAlignedSequence = new Vector();
				int nStart = i;
				String strFromChunkDB = "";
				while(i < vMapS.size() && (oPrev instanceof String || ((Integer)oPrev).intValue() != -1)){
					if(oPrev instanceof String && strFromChunkDB.compareTo((String)oPrev) != 0){
						String[] range = ((String)oPrev).split("_");
						int nLBound = Integer.parseInt(range[0]);
						int nUBound = Integer.parseInt(range[1]);
						for(int j = nLBound; j <= nUBound; j++){
							vAlignedSequence.add(new Integer(j));
							vAlignedSequenceIndex.add(vMapT.get(j));
						}
						strFromChunkDB = new String((String)oPrev);
					}
					else if(oPrev instanceof Integer){
						vAlignedSequence.add(oPrev);
						vAlignedSequenceIndex.add(new Integer(i));
					}
					i++;
					if(i < vMapS.size())
						oPrev = vMapS.get(i);
				}
				if(vAlignedSequence.size() > 0){
					i--;
					int nMin = -1;
					int nMax = -1;
					for(Iterator it3 = vAlignedSequence.iterator(); it3.hasNext(); ){
						int nToComp = ((Integer)it3.next()).intValue();
						if(nToComp != -999 && (nMin == -1 || nToComp < nMin))
							nMin = nToComp;
						if(nToComp != -999 && (nMax == -1 || nToComp > nMax))
							nMax = nToComp;
					}
					int nUnAligned = 0;
					Vector vSequenceRange = new Vector(1);
					int[] arrAlSeqSorted;
					if(nMin == -1 && nMax == -1)
						arrAlSeqSorted = new int[vAlignedSequence.size()];
					else
						arrAlSeqSorted = new int[nMax-nMin+1];
					for(int j = 0; j < arrAlSeqSorted.length; j++)
						arrAlSeqSorted[j] = -1;
					if(nMin != -1 && nMax != -1){
						for(Iterator it3 = vAlignedSequence.iterator(); it3.hasNext(); ){
							int nToSort = ((Integer)it3.next()).intValue();
							if(nToSort != -999)
								arrAlSeqSorted[nToSort-nMin] = nToSort;
						}
						String strRange = "";
						for(int j = 0; j < arrAlSeqSorted.length; j++)
							if(arrAlSeqSorted[j] == -1){
								Object oWhichSource = vMapT.get(j+nMin);
								if(oWhichSource instanceof Integer && ((Integer)oWhichSource).intValue() == -999)
									arrAlSeqSorted[j] = -999;
								else
									nUnAligned++;
							}
						
					/*	System.out.println("ARRAY OF TARGET INDEX");
						for(int j = 0; j < arrAlSeqSorted.length; j++)
							System.out.print(arrAlSeqSorted[j] + "\t");
						System.out.println();*/
					}
					
					if(nUnAligned == 0){
						Vector vPossRanges = null;
						int nCtr = 0;
						int nStartAl = -1;
						int nEndAl = -1;
						vPossRanges = new Vector();
						for(Iterator it3 = vAlignedSequence.iterator(); it3.hasNext() && nStartAl == -1; ){
							int nTargetAligned = ((Integer)it3.next()).intValue();
							if(nTargetAligned == -999){
								vPossRanges.add(vAlignedSequenceIndex.get(nCtr));
								vPossRanges.add(vAlignedSequenceIndex.get(nCtr));
							}
							else
								nStartAl = nCtr;
							nCtr++;
						}
						if(nStartAl != -1){
							int nInsertAt = vPossRanges.size();
							for(int j = vAlignedSequence.size()-1; j >= nStartAl && nEndAl == -1; j--){
								int nTargetAligned = ((Integer)vAlignedSequence.get(j)).intValue();
								if(nTargetAligned == -999){
									vPossRanges.add(nInsertAt, vAlignedSequenceIndex.get(j));
									vPossRanges.add((nInsertAt+1), vAlignedSequenceIndex.get(j));
								}
								else
									nEndAl = j;
							}
							vPossRanges.add(nInsertAt, vAlignedSequenceIndex.get(nStartAl));
							vPossRanges.add((nInsertAt+1), vAlignedSequenceIndex.get(nEndAl));
						}
						vRangeListS = addSourceRange(vPossRanges, vRangeListS, nTargetPtr);
					}
					else{
						Vector vPossRanges = new Vector();
						int nStart2 = -1;
						int nLBound = -1;
						int nUBound = -1;
						for(int j = 0; j < arrAlSeqSorted.length; j++)
							if(arrAlSeqSorted[j] != -1 && arrAlSeqSorted[j] != -999 && nStart2 == -1)
								nStart2 = j;
							else if(arrAlSeqSorted[j] == -1 && nStart2 != -1){
								int k = j - 1;
								while(arrAlSeqSorted[k] == -999)
									k--;
								vSequenceRange.add(arrAlSeqSorted[nStart2] + "-" + arrAlSeqSorted[k]);
								nStart2 = -1;
							}
						if(nStart2 != -1){
							int k = arrAlSeqSorted.length;
							do{
								k--;
							}while(arrAlSeqSorted[k] == -999);
							vSequenceRange.add(arrAlSeqSorted[nStart2] + "-" + arrAlSeqSorted[k]);
						}
						nStart2 = -1;
						boolean bHasAlignment = true;
						boolean bCanEnter = true;
						
						for(int j = 0; j < vAlignedSequence.size(); j++){
							int nToComp = ((Integer)vAlignedSequence.get(j)).intValue();
							if(nStart2 == -1){
								if(bCanEnter && nToComp == -999){
									vPossRanges.add(vAlignedSequenceIndex.get(j));
									vPossRanges.add(vAlignedSequenceIndex.get(j));
								}
								else{
									bCanEnter = false;
									nStart2 = j;
									bHasAlignment = true;
									for(Iterator it3 = vSequenceRange.iterator(); it3.hasNext(); ){
										String[] strPossRange = ((String)it3.next()).split("-");
										nLBound = Integer.parseInt(strPossRange[0]);
										nUBound = Integer.parseInt(strPossRange[1]);
										if(nToComp >= nLBound && nToComp <= nUBound)
											break;
									}
								}
							}
							else if(nStart2 != -1 && nToComp != -999 && (nToComp < nLBound || nToComp > nUBound)){
								j--;
								vPossRanges.add(vAlignedSequenceIndex.get(nStart2));
								vPossRanges.add(vAlignedSequenceIndex.get(j));
								nStart2 = -1;
								bHasAlignment = false;
							}
							else if(nToComp == -999){
								boolean bAllFcn = true;
								for(int k = j + 1; k < vAlignedSequence.size(); k++)
									if(((Integer)vAlignedSequence.get(k)).intValue() != -999)
										bAllFcn = false;
								if(bAllFcn){
									vPossRanges.add(vAlignedSequenceIndex.get(nStart2));
									vPossRanges.add(vAlignedSequenceIndex.get(j-1));
									nStart2 = -1;
									bHasAlignment = false;
									int nULimit = vAlignedSequence.size();
									for(int k = j; k < nULimit; k++){
										vPossRanges.add(vAlignedSequenceIndex.get(k));
										vPossRanges.add(vAlignedSequenceIndex.get(k));
									}
									j = nULimit-1;
								}
							}
						}
						if(nStart2 != -1){
							int j = vAlignedSequence.size()-1;
							vPossRanges.add(vAlignedSequenceIndex.get(nStart2));
							vPossRanges.add(vAlignedSequenceIndex.get(j));
						}
						vRangeListS = addSourceRange(vPossRanges, vRangeListS, nTargetPtr);
					}
				}
				else{
					Vector vRangeS = (Vector)vRangeListS.get(i);
					boolean bAlreadyHas = false;
					
					for(Iterator it4 = vRangeS.iterator(); it4.hasNext(); ){
						String strContent = it4.next().toString();
						if(strContent.startsWith("-1"))
							bAlreadyHas = true;
					}
					if(!bAlreadyHas){
						vRangeS.add(-1 + "#" + -1);
						vRangeS.add(new Integer(nTargetPtr));
						vRangeListS.setElementAt(vRangeS.clone(), i);
					}
				}
			}
			nTargetPtr++;
		}
		
		return getCombinationsPerSource(vRangeListS, vMapElementS);
	}
	
	/**	This function modifies vRangeList
	 *
	 *	vPossRanges - contains the lower and upper bounds in alternating order
	 *	vRangeList - contains the boundaries for splitting a Source chunk
	 *	nTargetPtr - indicates the row number in the Source-to-Target matrix that is referred
	 *		to by the modification
	 *
	 *	Returns the modified vRangeList
	 */
	protected Vector addSourceRange(Vector vPossRanges, Vector vRangeListS, int nTargetPtr){
		for(Iterator it = vPossRanges.iterator(); it.hasNext(); ){
			Object oStart = it.next();
			Object oEnd = it.next();
			int nStartTemp = -1;
			int nEndTemp = -1;
			
			if(oStart instanceof String){
				String[] arrStart = ((String)oStart).split("_");
				nStartTemp = Integer.parseInt(arrStart[0]);
			}
			else
				nStartTemp = ((Integer)oStart).intValue();
	
			if(oEnd instanceof String){
				String[] arrEnd = ((String)oEnd).split("_");
				nEndTemp = Integer.parseInt(arrEnd[1]);
			}
			else
				nEndTemp = ((Integer)oEnd).intValue();
				
			Vector vRangeS = (Vector)vRangeListS.get(nStartTemp);
			vRangeS.add(new String(nStartTemp + "#" + nEndTemp));
			vRangeS.add(new Integer(nTargetPtr));
			vRangeListS.setElementAt(vRangeS.clone(), nStartTemp);
		}
		return vRangeListS;
	}
	
	/**	This function gets all the possible ways the current Source chunk can be
	 *		split when compared to all the remaining unaligned Target chunks
	 *
	 *	vMapElementS - contains the Source-to-Target alignment matrix of a Source chunk
	 *	vRangeListS - contains the boundaries for splitting corresponding to vMapElementS
	 *	
	 */
	protected Vector getCombinationsPerSource(Vector vRangeListS, Vector vMapElementS){
		int[] arrCtr = new int[vRangeListS.size()];
		
		for(int i = 0; i < arrCtr.length; i++)
			arrCtr[i] = -1;
		
		int nCurrPtr = -1;
		Vector vStackOfIndices = new Vector(2);
		Vector vCandDivi = new Vector(2);
		String arrCandTarget[] = new String[vRangeListS.size()];
		String strRange;
		int nLBound = -1;
		int nUBound = -1;
		String[] strRangeLUBound;
		boolean bFinish = false;
		
		Vector vCandCombOfRanges = new Vector(2);
		Vector vStackOfRanges = new Vector(2);
		
		while(nCurrPtr + 1 < arrCtr.length && !bFinish){
			nCurrPtr++;
			arrCtr[nCurrPtr]++;
			if(arrCtr[nCurrPtr] < ((Vector)vRangeListS.get(nCurrPtr)).size()){
				strRange = (String)((Vector)vRangeListS.get(nCurrPtr)).get(arrCtr[nCurrPtr]);
				strRangeLUBound = strRange.split("#");
				nLBound = Integer.parseInt(strRangeLUBound[0]);
				nUBound = Integer.parseInt(strRangeLUBound[1]);
				arrCtr[nCurrPtr]++;
				if(nLBound == -1 && nUBound == -1){
					arrCandTarget[nCurrPtr] = new String("-1");
					nUBound = nCurrPtr;
				}
				else
					for(int i = nLBound; i <= nUBound; i++){
						int nWhichTarget = ((Integer)((Vector)vRangeListS.get(nCurrPtr)).get(arrCtr[nCurrPtr])).intValue();
						arrCandTarget[i] = new String(nWhichTarget + ">" + ((Vector)vMapElementS.get(nWhichTarget)).get(i));
					}
			}
			else if(vStackOfIndices.size() == 0){
				bFinish = true;
				continue;
			}
			if(nUBound + 1 == arrCtr.length && arrCtr[nCurrPtr] < ((Vector)vRangeListS.get(nCurrPtr)).size()){
				int nCandTarLength = arrCandTarget.length;
				
				boolean bHasUnAligned = false;
				for(int j = 0; j < arrCandTarget.length && !bHasUnAligned; j++)
					if(arrCandTarget[j].compareTo("-1") == 0)
						bHasUnAligned = true;
					
				if(!bHasUnAligned){
					String[] arrTemp = new String[nCandTarLength];
					int nLength = arrCandTarget.length;
					for(int j = 0; j < nLength; j++)
						arrTemp[j] = new String(arrCandTarget[j]);
						
					vCandDivi.add(arrTemp);
					vStackOfRanges.add(new String(((Vector)vRangeListS.get(nCurrPtr)).get(arrCtr[nCurrPtr]-1) + "<" + ((Vector)vRangeListS.get(nCurrPtr)).get(arrCtr[nCurrPtr])));
					vCandCombOfRanges.add(vStackOfRanges.clone());
					vStackOfRanges.remove(vStackOfRanges.size()-1);
				}
				nCurrPtr--;
			}
			else if(arrCtr[nCurrPtr] + 1 > ((Vector)vRangeListS.get(nCurrPtr)).size()){
				nCurrPtr = ((Integer)vStackOfIndices.remove(vStackOfIndices.size()-1)).intValue();
				for(int i = nCurrPtr+1; i < arrCtr.length; i++)
					arrCtr[i] = -1;
				nCurrPtr--;
				vStackOfRanges.remove(vStackOfRanges.size()-1);
			}
			else{
				vStackOfIndices.add(new Integer(nCurrPtr));
				vStackOfRanges.add(new String(((Vector)vRangeListS.get(nCurrPtr)).get(arrCtr[nCurrPtr]-1) + "<" + ((Vector)vRangeListS.get(nCurrPtr)).get(arrCtr[nCurrPtr])));
				nCurrPtr = nUBound;
			}
		}
	/*	System.out.println("FINAL vCandDivi!!!");
		for(int i = 0; i < vCandDivi.size(); i++){
			System.out.println("vCandDivi #" + (i+1));
			System.out.println(vCandCombOfRanges.get(i));
			String[] arrCandTemp = (String[])vCandDivi.get(i);
			for(int j = 0; j < arrCandTemp.length; j++)
				System.out.println(i + "-" + j + "--->" + arrCandTemp[j]);
		}*/
//
		vStackOfIndices = null;
		vStackOfRanges = null;
		System.gc();
//
		Vector vResults = new Vector(2);
		vResults.add(vCandDivi);
		vResults.add(vCandCombOfRanges);
		return vResults;
	}
	
	/**	This function ensures that no two Source tokens are aligned to the same Target token
	 *		to ensure that there would be no conflicts in the alignment.
	 *
	 *	vSourceCandidates - contains the Source-to-Target alignment matrices
	 *	vSCandRanges - contains the boundaries for splitting corresponding to vSourceCandidates
	 *
	 *	Returns all the possible combination of Source candidates such that for
	 *		each combination, there must be one candidate per Source chunk.
	 */
	protected Vector removeOverlapAlignment(Vector vSourceCandidates, Vector vSCandRanges){

		Vector vFinalSource = new Vector(vSourceCandidates.size());
		Vector vStackOfRanges = new Vector(vSourceCandidates.size());
		Vector vFinalSRanges = new Vector(vSourceCandidates.size());

		if(vSourceCandidates.size() == 1){
			Vector vCand = (Vector)vSourceCandidates.get(0);
			for(Iterator it = vCand.iterator(); it.hasNext(); ){
				Vector vIncluded = new Vector();
				vIncluded.add(it.next());
				vFinalSource.add(vIncluded);
			}
			Vector vCandRange = (Vector)vSCandRanges.get(0);
			for(Iterator it = vCandRange.iterator(); it.hasNext(); ){
				vStackOfRanges.add(it.next());
				vFinalSRanges.add(vStackOfRanges.clone());
				vStackOfRanges.clear();
			}
		}
		else{
			int[] arrCtr = new int[vSourceCandidates.size()];
			
			for(int i = 0; i < arrCtr.length; i++)
				arrCtr[i] = -1;
			
			int nCurrPtr = -1;
			Vector vStackOfIndices = new Vector(1);
			Vector vStackOfMappings = new Vector(1);
			boolean bFinish = false;
			while(nCurrPtr + 1 < arrCtr.length && !bFinish){
				nCurrPtr++;
				arrCtr[nCurrPtr]++;
				boolean bConflict = false;
				if(arrCtr[nCurrPtr] < ((Vector)vSourceCandidates.get(nCurrPtr)).size()){
					if(vStackOfMappings.size() > 0){
						String[] arrCandTarget = (String[])((Vector)vSourceCandidates.get(nCurrPtr)).get(arrCtr[nCurrPtr]);
						for(Iterator it = vStackOfMappings.iterator(); it.hasNext() && !bConflict; ){
							String[] arrCandTargetTemp = (String[])it.next();
							int nCandTargetSize = arrCandTarget.length;
							int nCandTargetSizeTemp = arrCandTargetTemp.length;
							for(int i = 0; i < nCandTargetSize && !bConflict; i++)
								for(int j = 0; j < nCandTargetSizeTemp && !bConflict; j++)
									if(arrCandTarget[i].compareTo("-1") != 0 && arrCandTargetTemp[j].compareTo("-1") != 0
										&& !(arrCandTarget[i].endsWith("-999")) && !(arrCandTargetTemp[j].endsWith("-999"))){
										if(arrCandTarget[i].contains("_") && arrCandTargetTemp[j].contains("_")){
											String[] strTarget = arrCandTarget[i].split(">");
											String[] strTargetRange = strTarget[1].split("_");
											int nLBound = Integer.parseInt(strTargetRange[0]);
											int nUBound = Integer.parseInt(strTargetRange[1]);
											
											String[] strTargetTemp = arrCandTargetTemp[j].split(">");
											String[] strTargetRangeTemp = strTargetTemp[1].split("_");
											int nLBoundTemp = Integer.parseInt(strTargetRangeTemp[0]);
											int nUBoundTemp = Integer.parseInt(strTargetRangeTemp[1]);
											
											if(strTarget[0].compareTo(strTargetTemp[0]) == 0)
												if((nLBoundTemp >= nLBound && nLBoundTemp <= nUBound)
													 || (nUBoundTemp >= nLBound && nUBoundTemp <= nUBound))
													 bConflict = true;
												else if((nLBound >= nLBoundTemp && nLBound <= nUBoundTemp)
													 || (nUBound >= nLBoundTemp && nUBound <= nUBoundTemp))
													 bConflict = true;
																					}
										else if(arrCandTarget[i].contains("_")){
											String[] strTarget = arrCandTarget[i].split(">");
											String[] strTargetRange = strTarget[1].split("_");
											int nLBound = Integer.parseInt(strTargetRange[0]);
											int nUBound = Integer.parseInt(strTargetRange[1]);
											
											String[] strTarget2 = arrCandTargetTemp[j].split(">");
											int nToComp = Integer.parseInt(strTarget2[1]);
											
											if(strTarget[0].compareTo(strTarget2[0]) == 0
												&& nToComp >= nLBound && nToComp <= nUBound)
												bConflict = true;
										}
										else if(arrCandTargetTemp[j].contains("_")){
											String[] strTarget = arrCandTargetTemp[j].split(">");
											String[] strTargetRange = strTarget[1].split("_");
											int nLBound = Integer.parseInt(strTargetRange[0]);
											int nUBound = Integer.parseInt(strTargetRange[1]);
											
											String[] strTarget2 = arrCandTarget[i].split(">");
											int nToComp = Integer.parseInt(strTarget2[1]);
											
											if(strTarget[0].compareTo(strTarget2[0]) == 0
												&& nToComp >= nLBound && nToComp <= nUBound)
												bConflict = true;
										}
										else if(arrCandTarget[i].compareTo(arrCandTargetTemp[j]) == 0)
											bConflict = true;
									}
						}
					}
				}
				else if(nCurrPtr == 0){
					bFinish = true;
					continue;
				}
				if(!bConflict){
					if(nCurrPtr + 1 == arrCtr.length && arrCtr[nCurrPtr] < ((Vector)vSourceCandidates.get(nCurrPtr)).size()){
						String[] arrMap1 = (String[])((Vector)vSourceCandidates.get(nCurrPtr)).get(arrCtr[nCurrPtr]);
						String[] arrMap2 = new String[arrMap1.length];
						for(int nTmpCtr = 0; nTmpCtr < arrMap1.length; nTmpCtr++)
							arrMap2[nTmpCtr] = new String(arrMap1[nTmpCtr]);
						vStackOfMappings.add(arrMap2);

						vFinalSource.add(vStackOfMappings.clone());
						vStackOfMappings.remove(vStackOfMappings.size()-1);
						Vector vStackElem1 = (Vector)(((Vector)vSCandRanges.get(nCurrPtr)).get(arrCtr[nCurrPtr])); 
						Vector vStackElem2 = new Vector(vStackElem1.size());
						for(Iterator it4 =  vStackElem1.iterator(); it4.hasNext(); )
							vStackElem2.add(new String((String)it4.next()));
						vStackOfRanges.add(vStackElem2);
						vFinalSRanges.add(vStackOfRanges.clone());
						vStackOfRanges.remove(vStackOfRanges.size()-1);
						nCurrPtr--;
					}
					else if(arrCtr[nCurrPtr] + 1 > ((Vector)vSourceCandidates.get(nCurrPtr)).size()){
						nCurrPtr = ((Integer)vStackOfIndices.remove(vStackOfIndices.size()-1)).intValue();
						vStackOfMappings.remove(vStackOfMappings.size()-1);
						for(int i = nCurrPtr+1; i < arrCtr.length; i++)
							arrCtr[i] = -1;
						nCurrPtr--;
						vStackOfRanges.remove(vStackOfRanges.size()-1);
					}
					else{
						vStackOfIndices.add(new Integer(nCurrPtr));
						String[] arrMap1 = (String[])((Vector)vSourceCandidates.get(nCurrPtr)).get(arrCtr[nCurrPtr]);
						String[] arrMap2 = new String[arrMap1.length];
						for(int nTmpCtr = 0; nTmpCtr < arrMap1.length; nTmpCtr++)
							arrMap2[nTmpCtr] = new String(arrMap1[nTmpCtr]);
						vStackOfMappings.add(arrMap2);
						
						Vector vStackElem1 = (Vector)((Vector)vSCandRanges.get(nCurrPtr)).get(arrCtr[nCurrPtr]); 
						Vector vStackElem2 = new Vector(vStackElem1.size());
						for(Iterator it4 =  vStackElem1.iterator(); it4.hasNext(); )
							vStackElem2.add(new String((String)it4.next()));
						vStackOfRanges.add(vStackElem2);
					}
				}
				else if(vStackOfMappings.size() > 0){
					System.out.println("..................CONFLICT ALERT!!!...................");
					
					nCurrPtr--;
				}
			}
		}
		
		Vector vResults = new Vector(2);
		vResults.add(vFinalSource);
		vResults.add(vFinalSRanges);
		return vResults;
	}
	
	/**	This function decomposes the given range (strRange) into a lower bound, an upper bound
	 *		and also the index of the Source or Target chunk the range refers to.
	 *
	 *	Returns the Vector containing the lower bound, the upper bound and the index of the
	 *		Source or Target chunk the strRange is pointing to.
	 */
	protected Vector getLUBound(String strRange1){
		String[] strDummy1 = strRange1.split("<");
		String[] strDummy2 = strDummy1[0].split("#");
		Vector vResults = new Vector(3);
		vResults.add(new Integer(Integer.parseInt(strDummy2[0])));
		vResults.add(new Integer(Integer.parseInt(strDummy2[1])));
		vResults.add(strDummy1[1]);
		return vResults;
	}
	
	/**	This function is the main function in the chunk splitting algorithm.  This computes for
	 *		all the possible alignments of the remaining unaligned Source and Target chunks. It
	 *		calls the functions that carry out the splitting process.
	 *
	 *	vCand - contains the Source-to-Target alignment matrices
	 *	vSCandRanges - contains the boundaries for splitting
	 *	vSChunks - contains the remaining unaligned Source chunks
	 *	vTChunks - contains the remaining unaligned Target chunks
	 *	vRemainSInd - contains the indices of the remaining unaligned Source chunks indicating
	 *		the position in the original given chunks
	 *	vRemainTInd - contains the indices of the remaining unaligned Target chunks indicating
	 *		the position in the original given chunks
	 *	vRemovedSInd - contains the indices of the aligned Source chunks indicating the
	 *		position in the original given chunks
	 *	vRemovedTInd - contains the indices of the aligned Target chunks indicating the
	 *		position in the original given chunks.
	 *
	 *	Returns the Vector of possible alignments.
	 *		index [0..n] - Vector containing the details of each possible alignments such that
	 *			for one possible alignment:
	 *		
	 *		index 0 - {@link String} index mapping of the splitted chunks and the index mapping of Source-to-Target alignment
	 *		index 1 - {@link Vector} containing the new Source {@link TExtChunk}s in the original order
	 *		index 2 - {@link Vector} containing the new Target {@link TExtChunk}s in the original order
	 *		index 3 - {@link Vector} containing the aligned Source {@link TExtChunk}s
	 *		index 4 - {@link Vector} containing the aligned Target {@link TExtChunk}s
	 *			such that the first element in index 3 is aligned to first element in index 4
	 */
	protected Vector splitChunks(Vector vCand, Vector vSCandRanges, Vector vSChunks, Vector vTChunks,
		Vector vRemainSInd, Vector vRemainTInd, Vector vRemovedSInd, Vector vRemovedTInd){
		Vector vResults = new Vector(1);
		
		int i = 0;
		for(Iterator it = vCand.iterator(), it2 = vSCandRanges.iterator(); it.hasNext() && it2.hasNext(); ){
			Vector vCandElemS = (Vector) ( (Vector)it.next()).clone();
			Vector vSCandRangesElem = (Vector)((Vector)it2.next()).clone();
			Vector vTCandRangesElem = new Vector();
			Vector vCandElemT = new Vector();
		
			Vector vRemainSIndTemp = (Vector)vRemainSInd.clone();
			Vector vRemainTIndTemp = (Vector)vRemainTInd.clone();
			Vector vRemovedSIndTemp = (Vector)vRemovedSInd.clone();
			Vector vRemovedTIndTemp = (Vector)vRemovedTInd.clone();
			Vector vOrigSCTemp = (Vector)vOrigSourceChunks.clone();
			Vector vOrigTCTemp = (Vector)vOrigTargetChunks.clone();
			Vector vAlSChunksTemp = (Vector)vAlignedSourceChunks.clone();
			Vector vAlTChunksTemp = (Vector)vAlignedTargetChunks.clone();
			StringBuffer sbDivMappingS = new StringBuffer("");
			StringBuffer sbDivMappingT = new StringBuffer("");
			StringBuffer sbAlMapping = new StringBuffer("");
			
			if(!checkIfValidChunks(vCandElemS, true))
				continue;
		
			for(int m = 0; m < vSCandRangesElem.size(); m++){
				TExtChunk cSource = (TExtChunk)vSChunks.get(m);
				Vector vRangePerSource = (Vector)vSCandRangesElem.get(m);
				String[] strCand = (String[])vCandElemS.get(m);
				for(int j = 0; j < vRangePerSource.size(); j++){
					String strRange = (String)vRangePerSource.get(j);
					Vector vBoundResults = getLUBound(strRange);
					int nLBound = ((Integer)vBoundResults.get(0)).intValue();
					int nUBound = ((Integer)vBoundResults.get(1)).intValue();
					boolean bHasAligned = false;
					for(int k = nLBound; k <= nUBound; k++)
						if(!(strCand[k].endsWith("-999")))
							bHasAligned = true;
					if(!bHasAligned){
						if(j == 0){
							String strRange1 = (String)vRangePerSource.remove(1);
							vBoundResults = getLUBound(strRange1);
							String strNewRange = new String(0 + "#" +  ((Integer)vBoundResults.get(1)).intValue() + "<" + vBoundResults.get(2));
							vRangePerSource.setElementAt(strNewRange, 0);
							j--;
						}
						else if(j == vRangePerSource.size()-1){
							String strRange1 = (String)vRangePerSource.remove(j-1);
							vBoundResults = getLUBound(strRange1);
							String strNewRange = new String(((Integer)vBoundResults.get(0)).intValue() + "#" + (strCand.length-1) + "<" + vBoundResults.get(2));
							vRangePerSource.setElementAt(strNewRange, j-1);
						}
						else{
							int nNext = j + 1;
							boolean bFoundAligned = false;
							while(!bFoundAligned && nNext < vRangePerSource.size()){
								String strNextRange = (String)vRangePerSource.get(nNext);
								vBoundResults = getLUBound(strNextRange);
								int nLBoundTemp = ((Integer)vBoundResults.get(0)).intValue();
								int nUBoundTemp = ((Integer)vBoundResults.get(1)).intValue();
								for(int k = nLBoundTemp; k <= nUBoundTemp; k++)
									if(!(strCand[k].endsWith("-999")))
										bFoundAligned = true;
								if(!bFoundAligned)
									nNext++;
							}
							if(!bFoundAligned){
								for(int k = nNext-1; k >= j; k--)
									vRangePerSource.remove(k);
								String strRange1 = (String)vRangePerSource.get(j-1);
								vBoundResults = getLUBound(strRange1);
								String strNewRange = new String(((Integer)vBoundResults.get(0)).intValue() + "#" + (strCand.length-1) + "<" + vBoundResults.get(2));
								vRangePerSource.setElementAt(strNewRange, j-1);
							} 
							else{
								String strFinalRange = (String)vRangePerSource.get(nNext-1);
								nUBound = ((Integer)getLUBound(strFinalRange).get(1)).intValue();
								int nStartPrefix = -1;
								for(int n = nLBound; n <= nUBound && nStartPrefix == -1; n++)
									if(cSource.size() > 0 && isPrefix((cSource.get(n)).toString(), true))
										nStartPrefix = n;
								if(nStartPrefix == -1){
									String strRange1 = (String)vRangePerSource.get(j-1);
									vBoundResults = getLUBound(strRange1);
									String strNewRange = new String(((Integer)vBoundResults.get(0)).intValue() + "#" + nUBound + "<" + vBoundResults.get(2));
									vRangePerSource.setElementAt(strNewRange, j-1);
								}
								else if(nStartPrefix == nLBound){
									String strRange1 = (String)vRangePerSource.get(nNext);
									vBoundResults = getLUBound(strRange1);
									String strNewRange = new String(nLBound + "#" + ((Integer)vBoundResults.get(1)).intValue() + "<" + vBoundResults.get(2));
									vRangePerSource.setElementAt(strNewRange, nNext);
								}
								else{
									String strRange1 = (String)vRangePerSource.get(j-1);
									vBoundResults = getLUBound(strRange1);
									String strNewRange = new String(((Integer)vBoundResults.get(0)).intValue() + "#" + (nStartPrefix-1) + "<" + vBoundResults.get(2));
									vRangePerSource.setElementAt(strNewRange, j-1);
									strRange1 = (String)vRangePerSource.get(nNext);
									vBoundResults = getLUBound(strRange1);
									strNewRange = new String(nStartPrefix + "#" + ((Integer)vBoundResults.get(1)).intValue() + "<" + vBoundResults.get(2));
									vRangePerSource.setElementAt(strNewRange, nNext);
								}
								for(int k = nNext-1; k >= j; k--)
									vRangePerSource.remove(k);
							}
						}
					}
				}
				vSCandRangesElem.setElementAt(vRangePerSource, m);
			}
		
			for(Iterator it3 = vTChunks.iterator(); it3.hasNext(); ){
				int nSize = ((TExtChunk)it3.next()).size();
				String[] arrTRange;
				if(nSize == 0)
					nSize = 1;
				arrTRange = new String[nSize];
				for(int j = 0; j < nSize; j++)
					arrTRange[j] = "-1";
				vCandElemT.add(arrTRange);
			}
			
		//#1	
			int nCtr1 = 0;
			for(Iterator it3 = vSCandRangesElem.iterator(); it3.hasNext(); ){
				Vector vRange = (Vector)it3.next();
				boolean bCanIncrement = true;
				for(int j = 0; j < vRange.size(); j++){
					String strRange = (String)vRange.get(j);
					String[] strDummy1 = strRange.split("<");
					String[] strDummy2 = strDummy1[0].split("#");
					if(strDummy2[0].compareTo("-1") != 0 && strDummy2[1].compareTo("-1") != 0){
						int nWhichTarget = Integer.parseInt(strDummy1[1]);
						int nLBound = Integer.parseInt(strDummy2[0]);
						int nUBound = Integer.parseInt(strDummy2[1]);
						String[] strCand = (String[])vCandElemS.get(nCtr1);
						
						String[] strTargetRange = (String[])vCandElemT.get(nWhichTarget);
						boolean bCurrUnAligned = true;
						for(int k = nLBound; k <= nUBound; k++){
							String[] strSource = strCand[k].split(">");
							if(strSource[1].contains("_")){
								String[] strLUBound = strSource[1].split("_");
								int nLBound2 = Integer.parseInt(strLUBound[0]);
								int nUBound2 = Integer.parseInt(strLUBound[1]);
								for(int m = nLBound2; m <= nUBound2; m++)
									strTargetRange[m] = nCtr1 + "," + j;
								bCurrUnAligned = false;
							}
							else{
								int nTargetPos = Integer.parseInt(strSource[1]);
								if(nTargetPos != -999){
									strTargetRange[nTargetPos] = nCtr1 + "," + j;
									bCurrUnAligned = false;
								}
							}
						}
						vCandElemT.setElementAt(strTargetRange, nWhichTarget);
					}
				}
				nCtr1++;
			}

		//#2
			nCtr1 = 0;
			for(Iterator it3 = vCandElemT.iterator(); it3.hasNext(); ){
				String[] strTargetRange = (String[])it3.next();
				for(int j = 0; j < strTargetRange.length; j++)
					if(strTargetRange[j].compareTo("-1") == 0){
						TExtChunk cTChunk = (TExtChunk)vTChunks.get(nCtr1);
						if(cTChunk.size() > 0){
							String strTargetToken = cTChunk.get(j).toString();
							if(isFunctionWord(strTargetToken, false))
								strTargetRange[j] = "-999," + strTargetToken;
						}
					}
				nCtr1++;
			}

			if(!checkIfValidChunks(vCandElemT, false))
				continue;
		//#3
			boolean bHasUnAlignedT = false;
			nCtr1 = 0;
			for(Iterator it3 = vCandElemT.iterator(); it3.hasNext() && !bHasUnAlignedT; ){
				String[] arrTarget = (String[])it3.next();
				boolean hasPrevFcn = false;
				TExtChunk cTarget = (TExtChunk)vTChunks.get(nCtr1);
				for(int j = 0; j < arrTarget.length && !bHasUnAlignedT; j++)
					if(arrTarget[j].compareTo("-1") == 0)
						bHasUnAlignedT = true;
				nCtr1++;
			}
			if(!bHasUnAlignedT){
		//#7
				nCtr1 = 0;
				for(Iterator it3 = vCandElemT.iterator(); it3.hasNext(); ){
					TExtChunk cTarget = (TExtChunk)vTChunks.get(nCtr1);
					String[] arrTarget = (String[])it3.next();
					boolean bHasAlignment = false;
					int nStartFcn = -1;
					for(int j = 0; j < arrTarget.length; j++){
						String strTargetRange = arrTarget[j];
						if(strTargetRange.startsWith("-999") && !bHasAlignment && nStartFcn == -1)
							nStartFcn = j;
						else if(strTargetRange.startsWith("-999") && nStartFcn == -1){
							int nTillWhichToken = -1;
							for(int k = j+1; k < arrTarget.length; k++)
								if(!(arrTarget[k].startsWith("-999"))){
									nTillWhichToken = k;
									break;
								}
							if(nTillWhichToken == -1){
								nTillWhichToken = arrTarget.length;
								for(int k = j; k < nTillWhichToken; k++)
									arrTarget[k] = arrTarget[j-1];
								j = nTillWhichToken;
							}
							else
								if(isPrefix(cTarget.get(j).toString(), false)){
									for(int k = j; k < nTillWhichToken; k++)
										arrTarget[k] = arrTarget[nTillWhichToken];
									j = nTillWhichToken;
								}
								else
									arrTarget[j] = arrTarget[j-1];
						}
						else if(!(strTargetRange.startsWith("-999")) && nStartFcn != -1){
							for(int k = nStartFcn; k < j; k++)
								arrTarget[k] = arrTarget[j];
							nStartFcn = -1;
							bHasAlignment = true;
						}
						else if(!(strTargetRange.startsWith("-999")))
							bHasAlignment = true;
					}
					nCtr1++;
				}
	//#8
				for(Iterator it3 = vCandElemT.iterator(); it3.hasNext(); ){
					String[] arrTarget = (String[])it3.next();
					String strSourceID = "";
					int nStartRange = 0;
					Vector vTRangePerChunk = new Vector();
					for(int j = 0; j < arrTarget.length; j++){
						String strTargetRange = arrTarget[j];
						if(strTargetRange.compareTo(strSourceID) != 0){
							if(strSourceID.compareTo("") != 0){
								String[] strDummy1 = strSourceID.split(",");
								vTRangePerChunk.add(nStartRange + "#" + (j-1) + "<" + Integer.parseInt(strDummy1[0]));
							}
							strSourceID = strTargetRange;
							nStartRange = j;
						}
					}
					String[] strDummy1 = strSourceID.split(",");
					vTRangePerChunk.add(nStartRange + "#" + (arrTarget.length-1) + "<" + Integer.parseInt(strDummy1[0]));
					vTCandRangesElem.add(vTRangePerChunk.clone());
				}
	//#9
				Vector vMapRes1 = makeDivisionMapping(vSCandRangesElem, vRemainSIndTemp, vRemainSInd, vRemovedSIndTemp);
				sbDivMappingS = (StringBuffer)vMapRes1.get(0);
				vSCandRangesElem = (Vector)vMapRes1.get(1);
				vRemainSIndTemp = (Vector)vMapRes1.get(2);
				vRemovedSIndTemp = (Vector)vMapRes1.get(3);
				Vector vMapRes2 = makeDivisionMapping(vTCandRangesElem, vRemainTIndTemp, vRemainTInd, vRemovedTIndTemp);
				sbDivMappingT = (StringBuffer)vMapRes2.get(0);
				vTCandRangesElem = (Vector)vMapRes2.get(1);
				vRemainTIndTemp = (Vector)vMapRes2.get(2);
				vRemovedTIndTemp = (Vector)vMapRes2.get(3);
	//#10
				if(vRemainSIndTemp.size() == vRemainTIndTemp.size()){
					int nNextAvailDomain = getNextDomain(vOrigSCTemp);
					nCtr1 = 0;
					vOrigSCTemp = removeRemFromOrig(vOrigSCTemp, vRemainSInd);
					vOrigTCTemp = removeRemFromOrig(vOrigTCTemp, vRemainTInd);
					
					Vector vDummy = makeNewChunks(vSChunks, vRemainSIndTemp, vSCandRangesElem, null, vOrigSCTemp);
					Vector vNewSChunks = (Vector)((Vector)vDummy.get(0)).clone();
					vOrigSCTemp = (Vector)((Vector)vDummy.get(1)).clone();
					
					vDummy = makeNewChunks(vTChunks, vRemainTIndTemp, vTCandRangesElem, vCandElemT, vOrigTCTemp);
					Vector vNewTChunks = (Vector)((Vector)vDummy.get(0)).clone();
					vOrigTCTemp = (Vector)((Vector)vDummy.get(1)).clone();
					
					for(Iterator it3 = vNewSChunks.iterator(); it3.hasNext(); ){
						TExtChunk cSource = (TExtChunk)it3.next();
						String strSDomTemp = cSource.domain();
						strSDomTemp = strSDomTemp.substring(1, strSDomTemp.length()-1);
						String[] strDummy1 = strSDomTemp.split(">");
						int nSRealIndex = Integer.parseInt(strDummy1[0]);
						int nTargetCtr = 0;
						int nTarget = -1;
						String strTDomTemp = "";
						for(Iterator it4 = vNewTChunks.iterator(); it4.hasNext(); ){
							strTDomTemp = ((TExtChunk)it4.next()).domain();
							if(strTDomTemp.endsWith(strDummy1[1] + "]")){
								nTarget = nTargetCtr;
								break;
							}
							nTargetCtr++;
						}
						vAlSChunksTemp.add(cSource);
						vAlTChunksTemp.add(vNewTChunks.remove(nTarget));
						vRemovedSIndTemp.add(new Integer(nSRealIndex));
						strDummy1 = strTDomTemp.split(">");
						vRemovedTIndTemp.add(new Integer(strDummy1[0].substring(1, strDummy1[0].length())));
					}	
					
					sbAlMapping = makeAlMapping(vRemovedSIndTemp, vRemovedTIndTemp);
					
					Vector vDummy1;
					
					vDummy1 = adjustChunkSize(vOrigSCTemp, vAlSChunksTemp, vRemovedSIndTemp);
					vOrigSCTemp = (Vector)((Vector)vDummy1.get(0)).clone();
					vAlSChunksTemp = (Vector)((Vector)vDummy1.get(1)).clone();
					
					vDummy1 = adjustChunkSize(vOrigTCTemp, vAlTChunksTemp, vRemovedTIndTemp);
					vOrigTCTemp = (Vector)((Vector)vDummy1.get(0)).clone();
					vAlTChunksTemp = (Vector)((Vector)vDummy1.get(1)).clone();

					if(nNextAvailDomain != -1){
						vDummy1 = adjustDomain(nNextAvailDomain, vOrigSCTemp, vAlSChunksTemp, vRemovedSIndTemp);
						vOrigSCTemp = (Vector)((Vector)vDummy1.get(0)).clone();
						vAlSChunksTemp = (Vector)((Vector)vDummy1.get(1)).clone();
					}
					
					Vector vCandAlignment = new Vector(5);
					vCandAlignment.add(sbDivMappingS.toString() + "**"
						+ sbDivMappingT.toString() + "**" + sbAlMapping.toString());
					vCandAlignment.add(vOrigSCTemp);
					vCandAlignment.add(vOrigTCTemp);
					vCandAlignment.add(vAlSChunksTemp);
					vCandAlignment.add(vAlTChunksTemp);
					vResults.add(vCandAlignment);
				}
			}
			i++;
		}
		return vResults;
	}
	
	/**	This function assigns domains to the chunks resulting from the split both in
	 *		vOrigCTemp and vAlChunksTemp.
	 *
	 *	nNextAvailDom contains the current highest domain that is being used.  vRemovedInd
	 *		contains the indices of the aligned chunks.
	 */
	protected Vector adjustDomain(int nNextAvailDom, Vector vOrigCTemp, Vector vAlChunksTemp, Vector vRemovedInd){
		int nOrigSize = vOrigCTemp.size();
		for(int j = 0; j < nOrigSize; j++){
			TExtChunk cChunk = (TExtChunk)vOrigCTemp.get(j);
			if(cChunk.size() > 0){
				cChunk.setDomain("[" + nNextAvailDom + "]");
				vOrigCTemp.setElementAt(cChunk, j);
				nNextAvailDom++;
				int nCtr1 = -1;
				for(Iterator it = vRemovedInd.iterator(); it.hasNext(); ){
					nCtr1++;
					if(((Integer)it.next()).intValue() == j){
						vAlChunksTemp.setElementAt(cChunk, nCtr1);
						break;
					}
				}
			}
		}
		Vector vResults = new Vector(2);
		vResults.add(vOrigCTemp);
		vResults.add(vAlChunksTemp);
		return vResults;
	}
	
	/**	This functions checks whether a chunk in vOrigCTemp and vAlChunksTemp contains only
	 *		a domain as an element.  If this is the case, the chunks are adjusted such that
	 *		there would be no element left and the value of the domain is assigned to the
	 *		domain variable of the chunk.  vRemovedInd contains the indices of the aligned
	 *		chunks.
	 */
	protected Vector adjustChunkSize(Vector vOrigCTemp, Vector vAlChunksTemp, Vector vRemovedInd){
		int nOrigSize = vOrigCTemp.size();
		for(int i = 0; i < nOrigSize; i++){
			TExtChunk cChunk = (TExtChunk)vOrigCTemp.get(i);
			if(cChunk.size() == 1 && cChunk.get(0) instanceof TExtChunk){
				Object oToken = cChunk.get(0);
				TExtChunk cNew = new TExtChunk(oToken.toString());
				vOrigCTemp.setElementAt(cNew, i);
				int nCtr1 = -1;
				for(Iterator it = vRemovedInd.iterator(); it.hasNext(); ){
					nCtr1++;
					if(((Integer)it.next()).intValue() == i){
						vAlChunksTemp.setElementAt(cNew, nCtr1);
						break;
					}
				}
				
			}
		}
		Vector vResults = new Vector(2);
		vResults.add(vOrigCTemp);
		vResults.add(vAlChunksTemp);
		return vResults;	
	}
	
	/**	This function calculates the next available domain that can be used by getting the
	 *		highest domain used in the given chunks (vOrigSCTemp).
	 */
	protected int getNextDomain(Vector vOrigSCTemp){
		double dMin = -1;
		
		for(Iterator it = vOrigSCTemp.iterator(); it.hasNext(); ){
			TExtChunk cSource = (TExtChunk)it.next();
			if(cSource.size() > 0){
				String strDomain = cSource.domain();
				double dDomain = Double.parseDouble(strDomain.substring(1, strDomain.length()-1));
				if(dMin == -1 || dMin > dDomain)
					dMin = dDomain;
			}
		}
		Double newMin = new Double(dMin);
		int nMin = newMin.intValue();
//
		newMin = null;
//
		return nMin;
	}
	
	/**	Given the original Vector of chunks, this function removes the chunks referred to
	 *		in the vRemainInd.  vRemainInd contains the indices of the remaining chunks.
	 *
	 *	This returns the Vector of original chunks less the unaligned ones.
	 */
	protected Vector removeRemFromOrig(Vector vOrigCTemp, Vector vRemainInd){
		int nCtr1 = 0;
		for(Iterator it = vRemainInd.iterator(); it.hasNext(); ){
			vOrigCTemp.remove(((Integer)it.next()).intValue()-nCtr1);
			nCtr1++;
		}
		return vOrigCTemp;
	}
	
	/**	Checks if all the remaining unaligned chunks are valid such that for a given
	 *		unaligned chunk, there must be at least 1 token that is not a function word.
	 *
	 *	vCandElem contains the matrix indicating which token is aligned to which token in the
	 *		other language for all the remaining unaligned Source and Target tokens. The
	 *		boolean isSource indicates whether vCandElem is a Source-to-Target alignment
	 *		matrix or a Target-to-Source matrix.
	 *
	 *	Returns true if all the unaligned chunks are valid otherwise, false.
	 */
	protected boolean checkIfValidChunks(Vector vCandElem, boolean isSource){
		boolean bAllChunksValid = true;
		for(Iterator it = vCandElem.iterator(); it.hasNext() && bAllChunksValid; ){
			String[] strCand = (String[])it.next();
			int nNumTokens = strCand.length;
			boolean hasNonFcn = false;
			for(int j = 0; j < nNumTokens && !hasNonFcn; j++){
				if(isSource && !(strCand[j].endsWith("-999")))
					hasNonFcn = true;
				else if(!isSource && !(strCand[j].startsWith("-999")))
					hasNonFcn = true;
			}
			if(!hasNonFcn)
				bAllChunksValid = false;
		}
		return bAllChunksValid;
	}
	
	/**	This function produces the index mapping of the original chunk and the resulting
	 *		chunks after the split.
	 *	
	 *	vCandRangesElem contains the boundaries of the new chunks that be result after the
	 *		splitting of the remaining original chunks.  vRemainIndTemp contains the indices
	 *		of the remaining unaligned chunks while vRemovedIndTemp contains the indices of
	 *		the aligned chunks.  vRemainInd contains the indices of the remaining unaligned
	 *		chunks before the splitting algorithm is employed.
	 *
	 *	Returns the index mapping in StringBuffer representation.
	 */
	protected Vector makeDivisionMapping(Vector vCandRangesElem, Vector vRemainIndTemp,
		Vector vRemainInd, Vector vRemovedIndTemp){
		
		int nCtr1 = 0;
		int nSCtr = 0;
		StringBuffer sbDivMapping = new StringBuffer("");
		for(Iterator it3 = vCandRangesElem.iterator(); it3.hasNext(); ){
			Vector vRangePerChunk = (Vector)it3.next();
			int nOffset = vRangePerChunk.size() - 1;
			if(nOffset > 0){
				int nCurrInd = ((Integer)vRemainIndTemp.get(nCtr1)).intValue();
				for(int j = nCtr1+1; j < vRemainIndTemp.size(); j++){
					int nInd = ((Integer)vRemainIndTemp.get(j)).intValue();
					vRemainIndTemp.setElementAt(new Integer(nInd+nOffset), j);
				}
				for(int j = nCtr1 + 1; j <= nCtr1 + nOffset; j++)
					vRemainIndTemp.add(j, new Integer(((Integer)vRemainIndTemp.get(nCtr1)).intValue()+(j-nCtr1)));
				for(int j = 0; j < vRemovedIndTemp.size(); j++){
					int nInd = ((Integer)vRemovedIndTemp.get(j)).intValue();
					if(nInd > nCurrInd)
						vRemovedIndTemp.setElementAt(new Integer(nInd+nOffset), j);
				}
				if(!(sbDivMapping.toString().compareTo("") == 0))
					sbDivMapping.append(";");
				int nStartSubInd = ((Integer)vRemainIndTemp.get(nCtr1)).intValue();
				sbDivMapping.append(vRemainInd.get(nSCtr) + ">" + nStartSubInd + "-" + (nStartSubInd+nOffset));
			}
			nCtr1 += (nOffset+1);
			nSCtr++;
		}

		Vector vResults = new Vector(4);
		vResults.add(sbDivMapping);
		vResults.add(vCandRangesElem);
		vResults.add(vRemainIndTemp);
		vResults.add(vRemovedIndTemp);
		return vResults;
	}
	
	/**	This function performs the actual splitting of chunks (vChunks) given the vCandRangesElem
	 *		which contains the index boundaries for the new chunks.  vRemainIndTemp contains
	 *		the indices of the remaining unaligned chunks based on the given order.
	 */
	protected Vector makeNewChunks(Vector vChunks, Vector vRemainIndTemp, Vector vCandRangesElem, Vector vCandElem, Vector vOrigCTemp){
		int nCtr1 = 0;
		int nCtr2 = 0;
		Vector vNewChunks = new Vector(vCandRangesElem.size());
		for(Iterator it3 = vCandRangesElem.iterator(); it3.hasNext(); ){
			TExtChunk cChunk = (TExtChunk)vChunks.get(nCtr1);
			String[] arrTarget = null;
			if(vCandElem != null)
				arrTarget = (String[])vCandElem.get(nCtr1);
			Vector vRange = (Vector)it3.next();
			int nCtr3 = 0;
			for(Iterator it4 = vRange.iterator(); it4.hasNext(); ){
				String strRange = (String)it4.next();
				String[] strDummy1 = strRange.split("<");
				String[] strDummy2 = strDummy1[0].split("#");
				int nLBound = Integer.parseInt(strDummy2[0]);
				int nUBound = Integer.parseInt(strDummy2[1]);
				Vector vTokens = new Vector();
				
				if(cChunk.size() == 0)
					vTokens.add(cChunk.domain());
				else
					for(int j = nLBound; j <= nUBound; j++)
						vTokens.add(cChunk.get(j));
				
				TExtChunk cNew;
				int nChunkPlace = ((Integer)vRemainIndTemp.get(nCtr2)).intValue();
				if(vCandElem == null)
					cNew = new TExtChunk(toStringChunk(vTokens),
						"[" + nChunkPlace + ">" + nCtr1 + "," + nCtr3 + "]",
						tlu.makeCompoundIdentifier(vTokens));
				else
					cNew = new TExtChunk(toStringChunk(vTokens),
						"[" + nChunkPlace + ">" + arrTarget[nLBound] + "]",
						tlu.makeCompoundIdentifier(vTokens));
				cNew = tlu.adjustChunkCompound(cNew);
				vNewChunks.add(cNew);
				vOrigCTemp.insertElementAt(cNew, nChunkPlace);
				nCtr2++;
				nCtr3++;
			}
			nCtr1++;
		}
		Vector vResults = new Vector(2);
		vResults.add(vNewChunks);
		vResults.add(vOrigCTemp);
		return vResults;
	}
	
	/**	This function produces the index mapping of the Source-to-Target alignment.
	 *	
	 *	vRemovedSIndTemp is a Vector containing the indices of the Source chunks while
	 *		vRemovedTIndTemp is a Vector containing the indices of the aligned Target
	 *		chunks such that the first element of vRemovedSIndTemp is aligned to the
	 *		first element of the vRemovedTIndTemp.
	 *
	 *	Returns the index mapping in StringBuffer representation.
	 */
	protected StringBuffer makeAlMapping(Vector vRemovedSIndTemp, Vector vRemovedTIndTemp){
		int nNumChunkS = vRemovedSIndTemp.size();
		int[] nMappedTarget = new int[nNumChunkS];
		
		for(Iterator it = vRemovedSIndTemp.iterator(), it2 = vRemovedTIndTemp.iterator(); it.hasNext() && it2.hasNext(); ){
			int nSource = ((Integer)it.next()).intValue();
			int nTarget = ((Integer)it2.next()).intValue();
			nMappedTarget[nSource] = nTarget;
		}
		
		StringBuffer sbSTMapping = new StringBuffer("");
		
		for(int j = 0; j < nNumChunkS; j++){
			if(!(sbSTMapping.equals("")))
				sbSTMapping.append(";");
			sbSTMapping.append(j + "-" + nMappedTarget[j]);
		}
		
		return sbSTMapping;
	}
	
	/**	Converts a chunks (represented as a Vector of tokens) to String.
	 */
	protected String toStringChunk(Vector vChunkTokens){
		StringBuffer sbChunk = new StringBuffer("");
		
		for(Iterator it = vChunkTokens.iterator(); it.hasNext(); )
			sbChunk = sbChunk.append((it.next()).toString() + " ");
		if(sbChunk.length() != 0)
			return sbChunk.substring(0, sbChunk.length()-1);
		else
			return sbChunk.toString();
	}

	/**	Checks if the given word (strWord) is a function word
	 */
	protected boolean isFunctionWord(String strWord, boolean isForSource){
		Vector vFunctionCheck;
		boolean isFunction = false;
		
		if(isForSource)
			if(bSourceIsFilipino)
				vFunctionCheck = vFunction1;
			else
				vFunctionCheck = vFunction2;
		else
			if(bSourceIsFilipino)
				vFunctionCheck = vFunction2;
			else
				vFunctionCheck = vFunction1;

		for(Iterator it = vFunctionCheck.iterator(); it.hasNext() && !isFunction; )
			if(strWord.compareToIgnoreCase((String)it.next()) == 0)
				isFunction = true;
//
		vFunctionCheck = null;
//	
		return isFunction;
	}
	
	/**	Checks if the given function word (strFcnWord) is a prefix
	 */
	protected boolean isPrefix(String strFcnWord, boolean isForSource){
		Vector vPrefixCheck;
		boolean isPrefix = false;
		
		if(isForSource)
			if(bSourceIsFilipino)
				vPrefixCheck = vFcnPrefix1;
			else
				vPrefixCheck = vFcnPrefix2;
		else
			if(bSourceIsFilipino)
				vPrefixCheck = vFcnPrefix2;
			else
				vPrefixCheck = vFcnPrefix1;

		for(Iterator it = vPrefixCheck.iterator(); it.hasNext() && !isPrefix; )
			if(strFcnWord.compareToIgnoreCase((String)it.next()) == 0)
				isPrefix = true;
//		
		vPrefixCheck = null;	
//
		return isPrefix;
	}
	
	/**	Given the Vector of possible alignments for the given chunks, this function removes
	 *		duplicate alignments based on the index of split mappings and index of Source-to-Target
	 *		mappings.  Alignments with the same mappings are removed.
	 */
	protected Vector removeDupAl(Vector vAlSplitResult){
		if(vAlSplitResult.size() < 2)
			return vAlSplitResult;
			
		for(int i = 0; i < vAlSplitResult.size(); i++){
			Vector vRes1 = (Vector)vAlSplitResult.get(i);
			for(int j = i+1; j < vAlSplitResult.size(); j++){
				Vector vRes2 = (Vector)vAlSplitResult.get(j);
				if(((String)vRes1.get(0)).compareTo((String)vRes2.get(0)) == 0){
					vAlSplitResult.remove(j);
					j--;
				}
				vRes2 = null;
			}
			vRes1 = null;
		}
		return vAlSplitResult;
	}

/*	public static void main(String args[]){
		//false = English Source
		//true = Filipino Source
		TExtLearnerUtility tlu = new TExtLearnerUtility(false);

		TExtChunk cSource1 = tlu.adjustChunkCompound(new TExtChunk("delicious and expensive [1]", "[17]", "none"));
//		TExtChunk cSource2 = tlu.adjustChunkCompound(new TExtChunk("Kat and", "[17]", "none"));
//		TExtChunk cSource3 = tlu.adjustChunkCompound(new TExtChunk("[2] went to Manila", "[17]", "none"));
		TExtChunk cTarget1 = tlu.adjustChunkCompound(new TExtChunk("matsalap at muhul na [1]", "[34]", "none"));
//		TExtChunk cTarget2 = tlu.adjustChunkCompound(new TExtChunk("Kat at", "[35]", "none"));
//		TExtChunk cTarget3 = tlu.adjustChunkCompound(new TExtChunk("pumunta [2] sa Manila", "[34]", "none"));
				
		Vector vSourceChunks = new Vector();
		vSourceChunks.add(cSource1);
//		vSourceChunks.add(cSource2);
//		vSourceChunks.add(cSource3);
		
		Vector vTargetChunks = new Vector();
		vTargetChunks.add(cTarget1);
//		vTargetChunks.add(cTarget2);
//		vTargetChunks.add(cTarget3);

		TExtTemplateRefiner tr = new TExtTemplateRefiner(false, tlu);
		Vector vResults = tr.getAlignmentInChunks(vSourceChunks, vTargetChunks);
		vSourceChunks = (Vector)vResults.get(0);
		vTargetChunks = (Vector)vResults.get(1);
		Hashtable htAlignedWords = (Hashtable)vResults.get(2);
		TExtChunkSplitter txtSplit = new TExtChunkSplitter(false, tlu);
		txtSplit.alignChunks(vSourceChunks, vTargetChunks, htAlignedWords, 0);
	}*/
}